其他
多点生活在 Service Mesh 上的实践 | 线上直播整理
Service Mesh Webinar 是由 ServiceMesher 社区和 CNCF 联合发起的线上直播活动,活动将不定期举行,为大家带来 Service Mesh 领域的知识和实践分享。
前言
为什么需要 Service Mesh 改造; 探索 Istio 技术点; Dubbo 场景下的改造;
为什么需要 Service Mesh 改造
安全; 配置中心; 调用链监控; 网关; 监控告警; 注册和发现; 容错和限流;
独立部署; 模块的边界; 技术多样性;
统一的服务治理; 服务治理和业务逻辑解耦;
增加运维复杂度; 增加延时; 需要更多技术栈;
探究 Istio 技术点
Source 是资源提供方(server),资源变化了之后推送给订阅者(Pilot),Istio 1.5 之前这个角色就是 Galley 或者自定义 MCP Server; Sink 是资源的订阅者(client),在 Istio 1.5 之前这个角色就是 Pilot 和 Mixer,都是订阅 Galley 或者自定义 MCP Server 的资源;
Pilot 启动后会读取 Configmap 的内容,里面有一个 configSources
的一个数组配置(Istio 1.5 之后没有这个配置,需要自己添加)、存放的是 MCP Server 的地址;Pilot 连接 MCPServer 之后发送所关注的资源请求; MCPServer 收到资源请求,检查请求的版本信息(可能为空),判断版本信息和当前最新维护的版本信息是否一致,不一致则触发 Push 操作,一致则不处理; Pilot 收到 Push 数据,处理返回的数据(数据列表可能为空,为空也标示处理成功),根据处理结果返回 ACK(成功)/ NACK(失败),返回的应答中包含返回数据的版本信息,如果返回的是 NACK,Pilot 会继续请求当前资源; MCPServer 收到 ACK(和资源请求一致)之后对比版本号,如果一致则不推送,否则继续推送最新数据;
MCPServer 自身数据发生变化,主动推送变化的资源给 Pilot; Pilot 收到之后处理这些数据,并根据处理结果返回 ACK / NACK; MCPServer 收到 ACK(和资源请求一致) 之后对比版本号,如果一致则不推送,否则继续推送最新数据;
更多 debug 接口可以查看: https://github.com/istio/istio/blob/5b926ddd5f0411aa50fa25c0a6f54178b758cec5/pilot/pkg/proxy/envoy/v2/debug.go#L103
根据不同平台(Kubernetes、Console)获取一些资源,Kubernetes 中使用 Informer 机制获取 Node、Endpoint、Service、Pod 变化; 根据用户的配置(CR、MCP 推送、文件)触发推送流程; 启动 gRPC server 用于接受 Sidecar 的连接;
记录变化的资源类型; 根据变化的资源类型(数组)整理本地数据; 根据变化的资源类型判断需要下发的 xDS 资源; 构建 xDS 资源,通过 gRPC 下发到连接到当前 Pilot 的 Sidecar;
协议部分(ADS、控制资源下发的顺序及返回确认的数据); 数据部分(CDS、EDS、LDS、RDS、SDS);
以上内容是根据源码整理:https://github.com/istio/istio/blob/5b926ddd5f0411aa50fa25c0a6f54178b758cec5/pilot/pkg/proxy/envoy/v2/ads_common.go#L97
mosn_config:MOSN 的配置信息; listener:LDS; routers:RDS; cluster:CDS 和 EDS;
address
就是 MOSN 监听的地址。network chains
,实现的还有:fault_inject; proxy; tcp_proxy;
network chains
同级的还有 listener chains
、 stream chains
, 其中 listener chains
目前只有 original_dst
实现。stream chains
可以对请求中的:StreamSender; StreamReceiver; StreamAccessLog;
BeforeRoute
AfterRoute
这些关键步骤进行修改请求信息。filter
都只有两种返回结果:Continue:如果后面还有 filter
那就执行后续filter
;Stop:执行完当前 filter
就不再继续执行了;
config
的内容, downstream_protocol
和 upstream_protocol
这里如果配置不一致,就需要协议转换。比如 HTTP1
转换为 HTTP2
,MOSN 就会先把 HTTP1
转换为 common
的中间协议,然后再把 common
转换为 HTTP2
,这样就实现了协议之间的转换。如果需要自己实现其他协议转换,那么只需要编写转换 common
的内容和 common
转换为当前协议的内容即可实现协议之间的互转。filters
里面的 proxy
,这个就是一个会经过路由的代理,配置信息里面配置了 router_config_name
,就是要路由的 router
名字。listener
里面的 proxy
的配置信息里面的 router_config_name
会找到一个 router
,如上图所示。然后就会根据请求里面的 domains
去匹配 virtual_hosts
, 这里的 domains
里面在 HTTP
里面就会是 host
,当在 Dubbo 协议里面我们可以把 service
(有些地方叫做 interface、target,我们这里统一叫 service) 放到 x-mosn-host
这个 MOSN 的 Header
里面,MOSN 就可以根据这个去匹配 domains
。virtual_hosts
之后,就会得到对应的 routers
,这里又会根据 match
里面的匹配规则进行匹配, HTTP
协议里面可以根据 path
、 queryparam
、 header
等信息进行匹配,具体匹配规则通过 VirtualService 下发,如果是 Dubbo 协议,那么可以套用 HTTPRoute
规则,然后把 Dubbo 的 attachment
解析出来当作 header
去用,目前 MOSN 没有解析 attachment
,我们自己实现了一个。route
,图中所示只有一个 cluster_name
,如果是有多个 subset
(DestinationRule 定义),那么就会有 weighted_cluster
,里面会有 cluster_name
和 weight
构成的对象的数组,例如:"route":{
"weighted_clusters":[
{
"cluster":{
"name":"outbound|20882|green|mosn.io.dubbo.DemoService.workload",
"weight":20
}
},
{
"cluster":{
"name":"outbound|20882|blue|mosn.io.dubbo.DemoService.workload",
"weight":80
}
}
],
"timeout":"0s",
"retry_policy":{
"retry_on":true,
"retry_timeout":"3s",
"num_retries":2
}
}
weight
之和必须为 100(Istio 定义的),必须是非负数的整数。timeout
、 retry_policy
服务策略。cluster_name
,然后我们再看 cluster
routers
里面匹配出来的 cluster_name
作为 key
在 cluster
里面会找到这么一个对象。lb_type
就是节点的负载均衡策略,目前 MOSN 支持:ROUNDROBIN; RANDOM; WEIGHTED_ROUNDROBIN; EAST_REQUEST;
hosts
里面的 address
里面也可以配置权重,这个权重必须是大于 0 或小于 129 的整数。可以通过 Istio 1.6 里面的 WorkloadEntry
来配置权重。然后根据负载均衡策略拿到 host
之后直接请求到对应的节点。Dubbo 场景下的改造
通过创建 EnvoyFilter 资源来给 xDS 资源打 patch; Envoy 解析 Dubbo 协议中的 Service 和 Method; 根据路由策略配置把流量转发到对应的 Provider;
MOSN 提供 Subscribe、Unsubscribe、Publish、Unpublish 的 HTTP 服务; SDK 发送请求到 MOSN 提供的这些服务,让 MOSN 代为与真正的注册中心交互; MOSN 通过 Dubbo-go 直接和注册中心连接;
数据面改造; 控制面适配;
20880 : provider 监听端口; 20881 : consumer 请求 MOSN 的这个端口,MOSN 做转发到 provider; 20882 : 接受来自下游(MOSN/consumer)的请求,直接转到 127.0.0.1:20880;
provider 启动之后请求本地 MOSN 的注册接口,把服务信息注册到注册中心(zk/nacos),注册请求到达 MOSN 之后,MOSN 会把注册端口号改为 20882; consumer 启动之后不需要连接注册中心,直接把请求发送到 127.0.0.1:20881; consumer 端的 MOSN 收到请求之后,根据配置信息 listener->routers->cluster->host,找到合适的 host(可以是 provider 的 MOSN 或者直接是 provider) 发送请求,这里的匹配过程可以修改 MOSN 让 Dubbo 的 service 作为 domains,attachment 作为 header; provider 端 MOSN 收到请求后(20882),直接转发请求到本地 127.0.0.1:20880;
Demo 演示
由于没有真正的注册,所以使用手动添加 ServiceEntry 的方式代替 Adapter 功能; Listener 和 Routers 配置信息目前是固定的; Provider 只注册到本地 ZK; Sidecar 注入到方式使用的是多个 Container;
istio-mosn-adapt-dubbo
。即使你没有 Kubernetes 环境也可以尝试的,后期这个会移植到 MOSN 官网,敬请期待。本期嘉宾介绍